﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using LumenLiquid;

/***********************************
 *             mimo_hos            *
 ***********************************/

namespace LumenLiquid._2D
{


    /// <summary>
    /// Class for an animation of individual 2D images
    /// </summary>
    class Sprite
    {

        #region Fields

        private TimeSpan _startTime = TimeSpan.Zero;//start time of the 
        private int _pPictures = 0;
        private int _currPicture = -1;//current picture to display
        private int _pHeight = 0;
        private int _pWidth = 0;
        private Texture2D _texture = null;//the texture to display
        private System.Drawing.Bitmap _sourcetexture = null;//the source bitmap. loaded in init
        private int _pDauer = 0;
        private bool _isReady = false;
        private int _pLoop = 1;//number of loops
        //private bool loopEndles = false;
        private int _currentLoop = 1;
        private int _pppr = 0;
        private int _startPic = 0;

        #endregion

        #region Constructors


        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param Name="bitmap"> The image with the animation </param>
        /// <param Name="Height"> The height of a single image </param>
        /// <param Name="Width"> The width of a single image </param>
        /// <param Name="Duration"> The duration of a single image </param>
        /// <param Name="Pictures"> The number of pictures </param>
        /// <param Name="device"> The device </param>
        /// <param Name="PPR"> The number of pictures in a row </param>>
        public Sprite(System.Drawing.Bitmap bitmap, int Width, int Height, int Duration, GraphicsDevice device)
        {
            int Pictures = (bitmap.Height / Height) * (bitmap.Width / Width);
            int PPR = bitmap.Width / Width;
            Init(bitmap, Width, Height, Duration, 1, Pictures, device, PPR, 1);
        }


        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param Name="bitmap"> The image with the animation </param>
        /// <param Name="Height"> The height of a single image </param>
        /// <param Name="Width"> The width of a single image </param>
        /// <param Name="Duration"> The duration of a single image </param>
        /// <param Name="Pictures"> The number of pictures </param>
        /// <param Name="device"> The device </param>
        /// <param Name="PPR"> The number of pictures in a row </param>
        /// <param name="loops">The number of repeats -1 means endless</param>
        public Sprite(System.Drawing.Bitmap bitmap, int Width, int Height, int Duration, GraphicsDevice device, int loops)
        {
            int Pictures = (bitmap.Height / Height) * (bitmap.Width / Width);
            int PPR = bitmap.Width / Width;
            Init(bitmap, Width, Height, Duration, 1, Pictures, device, PPR, loops);
        }


        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param Name="bitmap"> The image with the animation </param>
        /// <param Name="Height"> The height of a single image </param>
        /// <param Name="Width"> The width of a single image </param>
        /// <param Name="Duration"> The duration of a single image </param>
        /// <param Name="Pictures"> The final image </param>
        /// <param Name="StartPicture"> The opening image </param>
        /// <param Name="device"> The device </param>
        /// <param Name="PPR"> The number of pictures in a row </param>
        public Sprite(System.Drawing.Bitmap bitmap, int Width, int Height, int Duration, int StartPicture, int EndPicture, GraphicsDevice device, int PPR)
        {
            Init(bitmap, Width, Height, Duration, StartPicture, EndPicture, device, PPR, 1);
        }

        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param Name="bitmap"> The image with the animation </param>
        /// <param Name="Height"> The height of a single image </param>
        /// <param Name="Width"> The width of a single image </param>
        /// <param Name="Duration"> The duration of a single image </param>
        /// <param Name="Pictures"> The number of pictures </param>
        /// <param Name="device"> The device </param>
        /// <param Name="PPR"> The number of pictures in a row </param>
        /// <param Name="loop"> The number of repetitions. 999 for endless </param>
        public Sprite(System.Drawing.Bitmap bitmap, int Width, int Height, int Duration, int Pictures, GraphicsDevice device, int PPR, int loop)
        {
            Init(bitmap, Width, Height, Duration, 1, Pictures, device, PPR, loop);
        }

        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param Name="bitmap"> The image with the animation </param>
        /// <param Name="Height"> The height of a single image </param>
        /// <param Name="Width"> The width of a single image </param>
        /// <param Name="Duration"> The duration of a single image </param>
        /// <param Name="StartPicture"> The opening image </param>
        /// <param Name="EndPicture"> The final image </param>
        /// <param Name="device"> The device </param>
        /// <param Name="PPR"> The number of pictures in a row </param>
        ///  <param Name="loop"> The number of repetitions. 999 for endless </param>
        public Sprite(System.Drawing.Bitmap bitmap, int Width, int Height, int Duration, int StartPicture, int EndPicture, GraphicsDevice device, int PPR, int loop)
        {
            Init(bitmap, Width, Height, Duration, StartPicture, EndPicture, device, PPR, loop);
        }

        #endregion


        #region Functions

        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param Name="bitmap"> The image with the animation </param>
        /// <param Name="Height"> The height of a single image </param>
        /// <param Name="Width"> The width of a single image </param>
        /// <param Name="Lasting"> The duration of a single image </param>
        /// <param Name="StartPicture"> The opening image </param>
        /// <param Name="EndPicture"> The final image </param>
        /// <param Name="device"> The device </param>
        /// <param Name="PPR"> The number of pictures in a row </param>
        /// <param Name="loops"> The number of repetitions. 999 for endless </param>
        private void Init(System.Drawing.Bitmap bitmap, int Width, int Height, int Lasting, int StartPicture, int EndPicture, GraphicsDevice device, int PPR, int loops)
        {
            System.Drawing.Bitmap Destination = new System.Drawing.Bitmap(Width, Height);
            _sourcetexture = bitmap;
            this._pWidth = Width;
            this._pHeight = Height;
            this._pDauer = Lasting;
            this._pPictures = EndPicture - 1;
            this._currPicture = StartPicture - 1;
            this._startPic = StartPicture - 1;
            this._pLoop = loops;
            this._pppr = PPR;
            //if (loops == -1)
            //    loopEndles = true;

            System.Drawing.Graphics copyer = System.Drawing.Graphics.FromImage(Destination);
            System.Drawing.Rectangle Source;
            if ((_pppr - 1) < (_pPictures))
            {
                if (_currPicture != 0)
                {
                    Source = new System.Drawing.Rectangle((int)Rest(_currPicture, _pppr) * _pWidth, ((int)(_currPicture / _pppr)) * _pHeight, _pWidth, _pHeight);
                }
                else
                {
                    Source = new System.Drawing.Rectangle(0, 0, _pWidth, _pHeight);
                }
            }
            else
            {
                if (_currPicture != 0)
                {
                    Source = new System.Drawing.Rectangle(_currPicture * _pWidth, ((int)(_currPicture / _pppr)) * _pHeight, _pWidth, _pHeight);
                }
                else
                {
                    Source = new System.Drawing.Rectangle(0, 0, _pWidth, _pHeight);
                }
            }
            System.Drawing.Rectangle Dest = new System.Drawing.Rectangle(0, 0, Width, Height);

            copyer.DrawImage(bitmap, Dest, Source, System.Drawing.GraphicsUnit.Pixel);

            //System.IO.Stream Bitmap = null;
            //Destination.Save(Bitmap,System.Drawing.Imaging.ImageFormat.Gif);
            //texture = Texture2D.FromStream(device, Bitmap);

        }

        /// <summary>
        /// Return the current frame
        /// </summary>
        /// <param Name="device"> The device </param>
        /// <param Name="appTime"> The time since start of the game </param>
        /// <returns> A texture that contains the current frame </returns>
        public Texture2D GetCurrentImage(GraphicsDevice device, GameTime appTime)
        {
            if (_startTime == TimeSpan.Zero)
                _startTime = appTime.TotalGameTime;                                          //Fixed Bug by CShark&VisibleBasix old: startTime = appTime.ElapsedGameTime;

            //  if (startTime > TimeSpan.FromMilliseconds(doubledif))
            //    startTime = TimeSpan.Zero;
            // TimeSpan dif = appTime.ElapsedGameTime - startTime;
            TimeSpan diff = appTime.TotalGameTime.Subtract(StartTime);                      //Fixed Bug by CShark&VisibleBasix old: diff = appTime.ElapsedGameTime.Substract(StartTime);

            //TimeSpan diff = startTime.Subtract(appTime.ElapsedGameTime);
            double doubledif = diff.TotalMilliseconds;
            if (doubledif < 0)
                Global.DebugLog.Log("Sprite.cs: Error substracting two times");
            _currPicture = (int)((doubledif) / _pDauer) + _startPic;
            if (_currPicture > _pPictures)
            {
                if (_currentLoop == _pLoop)
                {
                    _currPicture = _pPictures;
                    _isReady = true;
                }
                else
                {
                    _currPicture = _startPic;
                    _startTime = appTime.TotalGameTime;                                      //Fixed Bug by CShark&VisibleBasix old: startTime = appTime.ElapsedGameTime;
                    _currentLoop++;
                }
            }

            System.Drawing.Bitmap Destination = new System.Drawing.Bitmap(_pWidth, _pHeight);

            System.Drawing.Graphics copyer = System.Drawing.Graphics.FromImage(Destination);
            System.Drawing.Rectangle Source;
            if ((_pppr - 1) < (_pPictures))
            {
                if (_currPicture != 0)
                {
                    Source = new System.Drawing.Rectangle((int)Rest(_currPicture, _pppr) * _pWidth, ((int)(_currPicture / _pppr)) * _pHeight, _pWidth, _pHeight);
                }
                else
                {
                    Source = new System.Drawing.Rectangle(0, 0, _pWidth, _pHeight);
                }
            }
            else
            {
                //return rectangle at current frame
                if (_currPicture != 0)
                {
                    Source = new System.Drawing.Rectangle(_currPicture * _pWidth, ((int)(_currPicture / _pppr)) * _pHeight, _pWidth, _pHeight);
                }
                else
                {
                    Source = new System.Drawing.Rectangle(0, 0, _pWidth, _pHeight);
                }
            }
            System.Drawing.Rectangle Dest = new System.Drawing.Rectangle(0, 0, _pWidth, _pHeight);

            copyer.DrawImage(_sourcetexture, Dest, Source, System.Drawing.GraphicsUnit.Pixel);

            System.IO.Stream Bitmap = new System.IO.MemoryStream();
            Destination.Save(Bitmap, System.Drawing.Imaging.ImageFormat.Gif);
            _texture = Texture2D.FromStream(device, Bitmap);
            Bitmap.Dispose();
            return _texture;

        }

        /// <summary>
        /// Set the animation to the beginning
        /// </summary>
        public void Reset()
        {
            _isReady = false;
            _currentLoop = 1;
            _currPicture = _startPic;
            _startTime = TimeSpan.Zero;
        }

        /// <summary>
        /// Pauses the animation
        /// </summary>
        public void Abort()
        {
            _isReady = true;
        }
        private double Rest(double X1, double X2)
        {
            double Temp = X1;

            do
            {
                Temp -= X2;
            } while (Temp >= X2);

            return Temp;
        }

        #endregion


        #region Prop


        /// <summary>
        /// Indicates whether the animation is finished
        /// </summary>
        public bool IsReady
        {
            get { return _isReady; }
        }

        /// <summary>
        /// The height of a single image
        /// </summary>
        public int Height
        {
            get { return _pHeight; }
        }

        /// <summary>
        /// The width of a single image
        /// </summary>
        public int Width
        {
            get { return _pWidth; }
        }



        /// <summary>
        /// Returns the number of frames in a row
        /// </summary>
        public int PicturesPerLine
        {
            get { return _pppr; }
        }

        /// <summary>
        /// Returns the time back a single image or set it
        /// </summary>
        public int Duration
        {
            get { return _pDauer; }
            set { _pDauer = value; }
        }

        /// <summary>
        /// Returns the number of frames shown
        /// </summary>
        public int Pictures
        {
            get { return _pPictures - _startPic; }

        }

        /// <summary>
        /// Sets or Returns the number of last frame
        /// </summary>
        public int EndPicture
        {
            get { return _pPictures; }
            set { _pPictures = value; }
        }


        /// <summary>
        /// Sets or returns the number of the start image
        /// </summary>
        public int StartPicture
        {
            get { return _startPic; }
            set { _startPic = value; }
        }

        /// <summary>
        /// Sets or returns the number of repetitions. 999 for continuous
        /// </summary>
        public int Loops
        {
            get { return _pLoop; }
            set { _pLoop = value; }
        }

        /// <summary>
        /// Returns the start time of the animation
        /// </summary>
        public TimeSpan StartTime
        {
            get { return _startTime; }
        }

        #endregion

    }
}
